home *** CD-ROM | disk | FTP | other *** search
/ The Very Best of Atari Inside / The Very Best of Atari Inside 1.iso / mint / mint110s / tty.c < prev    next >
C/C++ Source or Header  |  1994-01-31  |  20KB  |  832 lines

  1. /*
  2. Copyright 1990,1991,1992 Eric R. Smith.
  3. Copyright 1992,1993 Atari Corporation.
  4. All rights reserved.
  5. */
  6.  
  7. /*
  8.  * read/write routines for TTY devices
  9.  */
  10.  
  11. #include "mint.h"
  12.  
  13. static void _erase P_((FILEPTR *, int));
  14. static int escseq P_((struct tty *, int));
  15.  
  16. /* setting a special character to this value disables it */
  17. #define UNDEF 0
  18.  
  19.  
  20. /* default terminal characteristics */
  21.  
  22. struct tty default_tty = {
  23.     0,            /* process group */
  24.     0,            /* state */
  25.     0,            /* use_cnt */
  26.     0,            /* reserved short */
  27.     {
  28.     13, 13,            /* input speed == output speed == 9600 baud */
  29.     CTRL('H'),        /* erase */
  30.     CTRL('U'),        /* kill */
  31.     T_ECHO|T_CRMOD|T_TOSTOP|T_XKEY, /* flags */
  32.     },
  33.     {
  34.     CTRL('C'),        /* interrupt */
  35.     CTRL('\\'),        /* quit */
  36.     CTRL('Q'),        /* start */
  37.     CTRL('S'),        /* stop */
  38.     CTRL('D'),        /* EOF */
  39.     '\r'            /* alternate end of line */
  40.     },
  41.     {
  42.     CTRL('Z'),        /* suspend */
  43.     CTRL('Y'),        /* suspend after read */
  44.     CTRL('R'),        /* reprint */
  45.     UNDEF,            /* flush output */
  46.     CTRL('W'),        /* erase word */
  47.     CTRL('V')        /* quote next char */
  48.     },
  49.     {
  50.     0, 0, 0, 0        /* window size is unknown */
  51.     },
  52.     0,            /* no process is selecting us for reading */
  53.     0,            /* or for writing */
  54.     0            /* use default XKEY map */
  55. };
  56.  
  57. #define _put(f, c) (tty_putchar((f), (c), RAW))
  58.  
  59. static void
  60. _erase(f, c)
  61.     FILEPTR *f;
  62.     int c;
  63. {
  64.     _put(f, '\010');
  65.     _put(f, ' ');
  66.     _put(f, '\010');
  67. /* watch out for control characters -- they're printed as e.g. "^C" */
  68. /* BUG: \t is messed up. We really need to keep track of the output
  69.  * column
  70.  */
  71.     if (c >= 0 && c < ' ' && c != '\t') {
  72.         _put(f, '\010'); _put(f, ' '); _put(f, '\010');
  73.     }
  74. }
  75.  
  76. #define put(f, c)   { if (mode & T_ECHO) _put(f, c); }
  77. #define erase(f, c) { if (mode & T_ECHO) _erase(f, c); }
  78.  
  79. long
  80. tty_read(f, buf, nbytes)
  81.     FILEPTR *f;
  82.     void *buf;
  83.     long nbytes;
  84. {
  85.     long r;
  86.     long bytes_read = 0;
  87.     unsigned char ch, *ptr;
  88.     int rdmode, mode;
  89.     struct tty *tty;
  90.  
  91.     tty = (struct tty *)f->devinfo;
  92.     assert(tty != 0);
  93.  
  94.     if (f->flags & O_HEAD) {    /* pty server side? */
  95.         rdmode = RAW;        /* yes -- always raw mode */
  96.         mode = T_RAW;
  97.     }
  98.     else if (curproc->domain == DOM_MINT) {    /* MiNT domain process? */
  99.         mode = tty->sg.sg_flags;
  100.         rdmode = COOKED|NOECHO;
  101.         if ( mode & (T_RAW | T_CBREAK) ) {
  102.             rdmode = (mode & T_RAW) ? RAW : COOKED;
  103.         }
  104.         if (mode & T_XKEY)
  105.             rdmode |= ESCSEQ;
  106.     }
  107.     else {
  108.         rdmode = COOKED|NOECHO;
  109.         mode = T_TOS | T_ECHO;
  110.     }
  111.  
  112.     ptr = buf;
  113.  
  114.     while (bytes_read < nbytes) {
  115.         r = tty_getchar(f, rdmode);
  116.         if (r < 0) {
  117. tty_error:
  118.             DEBUG(("tty_read: tty_getchar returned %ld", r));
  119.             return (bytes_read) ? bytes_read : r;
  120.         }
  121.         else if (r == MiNTEOF)
  122.             return bytes_read;
  123.         ch = r & 0xff;
  124.  
  125.         if ( (mode & T_CRMOD) && (ch == '\r') )
  126.             ch = '\n';
  127.  
  128. /* 1 character reads in TOS mode are always raw */
  129.         if (nbytes == 1 && (mode & T_TOS)) {
  130.             put(f, ch);
  131.             *ptr = ch;
  132.             return 1;
  133.         }
  134.  
  135. /* T_CBREAK mode doesn't do erase or kill processing */
  136. /* also note that setting a special character to UNDEF disables it */
  137.  
  138.         if (rdmode & COOKED && !(mode & T_CBREAK) && ch != UNDEF) {
  139.             if ((char)ch == tty->sg.sg_erase) {  /* backspace */
  140.                 if (bytes_read > 0) {
  141.                     --ptr;
  142.                     erase(f, *ptr);
  143.                     bytes_read--;
  144.                 }
  145.                 continue;
  146.             }
  147.             else if ((mode & T_TOS) && ch == CTRL('X')) {
  148.                 while (bytes_read > 0) {
  149.                     --ptr;
  150.                     erase(f, *ptr);
  151.                     bytes_read--;
  152.                 }
  153.                 continue;
  154.             }
  155.             else if ((char)ch ==tty->ltc.t_rprntc || 
  156.                  (char)ch == tty->sg.sg_kill) {
  157.                 if (mode & T_TOS)
  158.                     put(f, '#');
  159.                 put(f, '\r');
  160.                 put(f, '\n');
  161.                 ptr = buf;
  162.                 if ((char)ch == tty->sg.sg_kill) {
  163.                     bytes_read = 0;
  164.                 }
  165.                 else {
  166.                     for (r = 0; r < bytes_read; r++, ptr++)
  167.                         put(f, *ptr);
  168.                 }
  169.                 continue;
  170.             }
  171.             else if ((char)ch == tty->ltc.t_werasc) {
  172.                 while (bytes_read > 0 &&
  173.                        !(ptr[-1] == ' ' || ptr[-1] == '\t')) {
  174.                     ptr--;
  175.                     erase(f, *ptr);
  176.                     bytes_read--;
  177.                 }
  178.                 continue;
  179.             }
  180.             else if ((char)ch == tty->ltc.t_lnextc) {
  181.                 put(f, '^');
  182.                 put(f, '\b');
  183.                 r = tty_getchar(f, RAW);
  184.                 if (r < 0)
  185.                     goto tty_error;
  186.                 else if (r == MiNTEOF)
  187.                     return bytes_read;
  188.                 ch = r & 0xff;
  189.                 goto stuff_it;
  190.             }
  191.             else if ((char)ch == tty->tc.t_eofc && !(mode & T_TOS))
  192.                 return bytes_read;
  193.         }
  194.  
  195. /* both T_CBREAK and T_COOKED modes have to do signals, though */
  196.         if ((rdmode & COOKED) && ch != UNDEF) {
  197.             if ((char)ch == tty->tc.t_intrc
  198.                  || (char)ch == tty->tc.t_quitc
  199.                  || (char)ch == tty->ltc.t_dsuspc
  200.                  || (char)ch == tty->ltc.t_suspc
  201.                 ) {
  202. /* the device driver raised the appropriate signal; if we get here, the
  203.    signal was caught by the user (or ignored). flush buffers and continue
  204.  */
  205.                 if (!(tty->sg.sg_flags & T_NOFLSH)) {
  206.                     DEBUG(("tty_read: flushing input"));
  207.                     bytes_read = 0;
  208.                     ptr = buf;
  209.                 }
  210.                 continue;
  211.             }
  212.             else if (ch == '\n' || (char)ch == tty->tc.t_brkc) {
  213.                 put(f, '\r');
  214.                 if (!(mode & T_TOS)) {
  215.                     *ptr = ch;
  216.                     put(f, '\n');
  217.                     bytes_read++;
  218.                 }
  219.                 return bytes_read;
  220.             }
  221.  
  222.         }
  223.  
  224. /* do the following for both RAW and COOKED mode */
  225. stuff_it:
  226.         *ptr++ = ch;
  227.         if (ch < ' ' && ch != '\t') {    /* ch is unsigned */
  228.             put(f, '^'); put(f, ch+'@');
  229.         }
  230.         else
  231.             put(f, ch);
  232.         bytes_read++;
  233.  
  234. /* for RAW mode, if there are no more characters then break */
  235.         if ( (mode & (T_RAW|T_CBREAK)) &&
  236.             !((rdmode & ESCSEQ) && (tty->state & TS_ESC))) {
  237.             r = 1;
  238.             (void)(*f->dev->ioctl)(f, FIONREAD, &r);
  239.             if (r <= 0) break;
  240.         }    
  241.     }
  242.  
  243.     return bytes_read;
  244. }
  245.  
  246. long
  247. tty_write(f, buf, nbytes)
  248.     FILEPTR *f;
  249.     const void *buf;
  250.     long nbytes;
  251. {
  252.     unsigned const char *ptr;
  253.     long c;
  254.     long bytes_written;
  255.     int mode, rwmode;
  256.     struct tty *tty;
  257.     int use_putchar = 0;
  258.     static long cr_char = '\r';
  259. #define LBUFSIZ 128
  260.     long lbuf[LBUFSIZ];
  261.  
  262.     tty = (struct tty *)f->devinfo;
  263.     assert(tty != 0);
  264.  
  265.     ptr = buf;
  266.     if (f->flags & O_HEAD) {
  267.         use_putchar = 1;
  268.         mode = T_RAW;
  269.     }
  270.     else if (curproc->domain == DOM_TOS)
  271. /* for TOS programs, 1 byte writes are always in raw mode */
  272.         mode = (nbytes == 1) ? T_RAW : T_TOS;
  273.     else
  274.         mode = tty->sg.sg_flags;
  275.  
  276.     rwmode = (mode & T_RAW) ? RAW : COOKED;
  277.  
  278.     bytes_written = 0;
  279.  
  280. /*
  281.  * "mode" can now be reduced to just T_CRMODE or not
  282.  */
  283.     if ((curproc->domain == DOM_MINT) && (mode & T_CRMOD) &&
  284.         !(mode & T_RAW))
  285.         mode = T_CRMOD;
  286.     else
  287.         mode = 0;
  288.  
  289. /*
  290.  * we always write at least 1 byte with tty_putchar, since that takes
  291.  * care of job control and terminal states. After that, we may be able
  292.  * to use (*f->dev->write) directly.
  293.  */
  294.  
  295.  
  296.     if (nbytes == 0) return bytes_written;
  297.     c = *ptr++;
  298.  
  299.     if (c == '\n' && mode) {    /* remember, "mode" now means CRMOD */
  300.         tty_putchar(f, cr_char, rwmode);
  301.     }
  302.     tty_putchar(f, c, rwmode);
  303.     nbytes--;
  304.     bytes_written++;
  305.  
  306.     if (use_putchar) {
  307.         while (nbytes-- > 0) {
  308.             c = *ptr++;
  309.             if (c == '\n' && mode)
  310.                 tty_putchar(f, cr_char, rwmode);
  311.             tty_putchar(f, c, rwmode);
  312.             bytes_written++;
  313.         }
  314.     } else {
  315. /* write in big chunks if possible; but never more than 1 line
  316.  * (so that ^S/^Q can happen reasonably quickly for the user)
  317.  */
  318.         long bytes_to_write = 0;
  319.         long *s = lbuf;
  320.  
  321.         while (nbytes-- > 0) {
  322.             c = *ptr++;
  323.             if (c == '\n') {
  324.                 if (bytes_to_write) {
  325.                     (*f->dev->write)(f, (char *)lbuf,
  326.                         bytes_to_write);
  327.                     bytes_to_write = 0;
  328.                     s = lbuf;
  329.                 }
  330.                 if (mode)    /* i.e. T_CRMODE */
  331.                     tty_putchar(f, cr_char, rwmode);
  332.                 tty_putchar(f, (long)c, rwmode);
  333.                 bytes_written++;
  334.             } else {
  335.                 *s++ = c;
  336.                 bytes_written++;
  337.                 bytes_to_write += 4;
  338.                 if (bytes_to_write >= LBUFSIZ*4) {
  339.                     (*f->dev->write)(f, (char *)lbuf,
  340.                              bytes_to_write);
  341.                     bytes_to_write = 0;
  342.                     s = lbuf;
  343.                 }
  344.             }
  345.         }
  346.         if (bytes_to_write) {
  347.             (*f->dev->write)(f, (char *)lbuf, bytes_to_write);
  348.         }
  349.     }
  350.  
  351.     return bytes_written;
  352. }
  353.  
  354. /* some notable scan codes */
  355. #define K_INSERT    0x52
  356. #define K_HOME        0x47
  357. #define K_UNDO        0x61
  358. #define K_HELP        0x62
  359. #define CURS_UP        0x48
  360. #define CURS_DN        0x50
  361. #define CURS_RT        0x4d
  362. #define CURS_LF        0x4b
  363. #define F_1        0x3b
  364. #define F_10        0x44
  365. #define F_11        0x54
  366. #define F_20        0x5d
  367. #define ALT_1        0x78
  368. #define ALT_0        0x81
  369.  
  370. /* Default function key table:
  371.  * entries:    0-9 are F1-F10
  372.  *            10-19 are F11-F20
  373.  *        20-23 are cursor up, down, right, and left
  374.  *        24-27 are help, undo, insert, and home
  375.  *        28-31 are shift+cursor up, down, right, and left
  376.  */
  377.  
  378. static char vt52xkey[256] = {
  379. '\033', 'P', 0, 0, 0, 0, 0, 0,
  380. '\033', 'Q', 0, 0, 0, 0, 0, 0,
  381. '\033', 'R', 0, 0, 0, 0, 0, 0,
  382. '\033', 'S', 0, 0, 0, 0, 0, 0,
  383. '\033', 'T', 0, 0, 0, 0, 0, 0,
  384. '\033', 'U', 0, 0, 0, 0, 0, 0,
  385. '\033', 'V', 0, 0, 0, 0, 0, 0,
  386. '\033', 'W', 0, 0, 0, 0, 0, 0,
  387. '\033', 'X', 0, 0, 0, 0, 0, 0,
  388. '\033', 'Y', 0, 0, 0, 0, 0, 0,
  389. '\033', 'p', 0, 0, 0, 0, 0, 0,
  390. '\033', 'q', 0, 0, 0, 0, 0, 0,
  391. '\033', 'r', 0, 0, 0, 0, 0, 0,
  392. '\033', 's', 0, 0, 0, 0, 0, 0,
  393. '\033', 't', 0, 0, 0, 0, 0, 0,
  394. '\033', 'u', 0, 0, 0, 0, 0, 0,
  395. '\033', 'v', 0, 0, 0, 0, 0, 0,
  396. '\033', 'w', 0, 0, 0, 0, 0, 0,
  397. '\033', 'x', 0, 0, 0, 0, 0, 0,
  398. '\033', 'y', 0, 0, 0, 0, 0, 0,
  399. '\033', 'A', 0, 0, 0, 0, 0, 0,
  400. '\033', 'B', 0, 0, 0, 0, 0, 0,
  401. '\033', 'C', 0, 0, 0, 0, 0, 0,
  402. '\033', 'D', 0, 0, 0, 0, 0, 0,
  403. '\033', 'H', 0, 0, 0, 0, 0, 0,
  404. '\033', 'K', 0, 0, 0, 0, 0, 0,
  405. '\033', 'I', 0, 0, 0, 0, 0, 0,
  406. '\033', 'E', 0, 0, 0, 0, 0, 0,
  407. '\033', 'a', 0, 0, 0, 0, 0, 0,
  408. '\033', 'b', 0, 0, 0, 0, 0, 0,
  409. '\033', 'c', 0, 0, 0, 0, 0, 0,
  410. '\033', 'd', 0, 0, 0, 0, 0, 0,
  411. };
  412.  
  413. static char unxbaud P_((long));
  414.  
  415. /* convert a number describing the baud rate into a Unix
  416.  * style baud rate number. Returns the Unix baud rate,
  417.  * or 16 (EXTA) if the rate is unknown
  418.  */
  419.  
  420. #define EXTA 16
  421.  
  422. static long ubaud[EXTA] = {
  423. 0L, 50L, 75L, 110L, 134L, 150L, 200L, 300L,
  424. 600L, 1200L, 1800L, 2400L, 4800L, 9600L, 19200L, 38400L
  425. };
  426.  
  427. static char
  428. unxbaud(baud)
  429.     long baud;
  430. {
  431.     int i;
  432.     for (i = 1; i < EXTA; i++) {
  433.         if (ubaud[i] == baud)
  434.             break;
  435.     }
  436.     return i;
  437. }
  438.  
  439. #define tosbaud(c) ( ((c) < 0 || (c) >= EXTA) ? -1L : ubaud[(unsigned)c] )
  440.  
  441. long
  442. tty_ioctl(f, mode, arg)
  443.     FILEPTR *f;
  444.     int mode;
  445.     void *arg;
  446. {
  447.     struct sgttyb *sg;
  448.     struct tchars *tc;
  449.     struct ltchars *ltc;
  450.     struct tty *tty;
  451.     struct winsize *sz;
  452.     struct xkey *xk;
  453.     char *xktab;
  454.     int i;
  455.     long baud;
  456.     short flags;
  457.  
  458.     if (!is_terminal(f)) {
  459.         DEBUG(("tty_ioctl(mode %x): file is not a tty", mode));
  460.         return EINVFN;
  461.     }
  462.     tty = (struct tty *)f->devinfo;
  463.     assert(tty != 0);
  464.  
  465.     switch(mode) {
  466.     case TIOCGETP:
  467.         sg = (struct sgttyb *)arg;
  468.     /* get input and output baud rates from the terminal device */
  469.         baud = -1L;
  470.         (*f->dev->ioctl)(f, TIOCIBAUD, &baud);
  471.         tty->sg.sg_ispeed = unxbaud(baud);
  472.         baud = -1L;
  473.         (*f->dev->ioctl)(f, TIOCOBAUD, &baud);
  474.         tty->sg.sg_ospeed = unxbaud(baud);
  475.     /* get terminal flags */
  476.         flags = 0;
  477.         if ((*f->dev->ioctl)(f, TIOCGFLAGS, &flags) == 0) {
  478.             tty->sg.sg_flags &= ~TF_FLAGS;
  479.             tty->sg.sg_flags |= (flags & TF_FLAGS);
  480.         }
  481.         *sg = tty->sg;
  482.         return 0;
  483.     case TIOCSETP:
  484.         sg = (struct sgttyb *)arg;
  485.         tty->sg = *sg;
  486.     /* set baud rates */
  487.         baud = tosbaud(sg->sg_ispeed);
  488.         (*f->dev->ioctl)(f, TIOCIBAUD, &baud);
  489.         baud = tosbaud(sg->sg_ospeed);
  490.         (*f->dev->ioctl)(f, TIOCOBAUD, &baud);
  491.     /* set parity, etc. */
  492.         flags = TF_8BIT;
  493.         if (sg->sg_flags & (T_EVENP|T_ODDP)) {
  494.             flags = TF_7BIT;
  495.         }
  496.         flags |= (sg->sg_flags & TF_FLAGS);
  497.         (*f->dev->ioctl)(f, TIOCSFLAGS, &flags);
  498.         return 0;
  499.     case TIOCGETC:
  500.         tc = (struct tchars *)arg;
  501.         *tc = tty->tc;
  502.         return 0;
  503.     case TIOCSETC:
  504.         tc = (struct tchars *)arg;
  505.         tty->tc = *tc;
  506.         return 0;
  507.     case TIOCGLTC:
  508.         ltc = (struct ltchars *)arg;
  509.         *ltc = tty->ltc;
  510.         return 0;
  511.     case TIOCSLTC:
  512.         ltc = (struct ltchars *)arg;
  513.         tty->ltc = *ltc;
  514.         return 0;
  515.     case TIOCGWINSZ:
  516.         sz = (struct winsize *)arg;
  517.         *sz = tty->wsiz;
  518.         return 0;
  519.     case TIOCSWINSZ:
  520.         sz = (struct winsize *)arg;
  521.         tty->wsiz = *sz;
  522.         return 0;
  523.     case TIOCGPGRP:
  524.         *((long *)arg) = tty->pgrp;
  525.         return 0;
  526.     case TIOCSPGRP:
  527.         tty->pgrp = (*((long *)arg) & 0x00007fffL);
  528.         return 0;
  529.     case TIOCSTART:
  530.         tty->state &= ~TS_HOLD;
  531.         return 0;
  532.     case TIOCSTOP:
  533.         tty->state |= TS_HOLD;
  534.         return 0;
  535.     case TIOCGXKEY:
  536.         xk = (struct xkey *)arg;
  537.         i = xk->xk_num;
  538.         if (i < 0 || i > 31) return ERANGE;
  539.         xktab = tty->xkey;
  540.         if (!xktab) xktab = vt52xkey;
  541.         xktab += i*8;
  542.         for (i = 0; i < 8; i++)
  543.             xk->xk_def[i] = *xktab++;
  544.         return 0;
  545.     case TIOCSXKEY:
  546.         xk = (struct xkey *)arg;
  547.         xktab = tty->xkey;
  548.         if (!xktab) {
  549.             xktab = kmalloc((long)256);
  550.             if (!xktab) return ENSMEM;
  551.             for (i = 0; i < 256; i++)
  552.                 xktab[i] = vt52xkey[i];
  553.             tty->xkey = xktab;
  554.         }
  555.         i = xk->xk_num;
  556.         if (i < 0 || i > 31) return ERANGE;
  557.         xktab += i*8;
  558.         for (i = 0; i < 7; i++)
  559.             xktab[i] = xk->xk_def[i];
  560.         xktab[7] = 0;
  561.         return 0;
  562.     default:
  563.         DEBUG(("tty_ioctl: bad function call"));
  564.         return EINVFN;
  565.     }
  566. }
  567.  
  568. /*
  569.  * function for translating extended characters (e.g. cursor keys, or
  570.  * ALT+key sequences) into either escape sequences or meta characters.
  571.  * for escape sequences, we return the the first character of the
  572.  * sequence (normally ESC) and set the tty's state so that subsequent
  573.  * calls to tty_getchar will pick up the remaining characters.
  574.  * Note that escape sequences are limited to 7 characters at most.
  575.  */
  576.  
  577. static int
  578. escseq(tty, scan)
  579.     struct tty *tty;
  580.     int scan;
  581. {
  582.     char *tab;
  583.     int i;
  584.  
  585.     switch(scan) {
  586.     case CURS_UP: i = 20; break;
  587.     case CURS_DN: i = 21; break;
  588.     case CURS_RT: i = 22; break;
  589.     case CURS_LF: i = 23; break;
  590.     case K_HELP:  i = 24; break;
  591.     case K_UNDO:  i = 25; break;
  592.     case K_INSERT:i = 26; break;
  593.     case K_HOME:  i = 27; break;
  594.     case CURS_UP+0x100: i = 28; break;
  595.     case CURS_DN+0x100: i = 29; break;
  596.     case CURS_RT+0x100: i = 30; break;
  597.     case CURS_LF+0x100: i = 31; break;
  598.     default:
  599.         if (scan >= F_1 && scan <= F_10) {
  600.             i = scan - F_1;
  601.         } else if (scan >= F_11 && scan <= F_20) {
  602.             i = 10 + scan - F_11;
  603.         } else
  604.             i = -1;
  605.     }
  606.  
  607.     if (i >= 0) {        /* an extended escape sequence */
  608.         tab = tty->xkey;
  609.         if (!tab) tab = vt52xkey;
  610.         i *= 8;
  611.         scan = tab[i++];
  612.         if (scan) {
  613.             if (tab[i] == 0) i = 0;
  614.             tty->state = (tty->state & ~TS_ESC) | i;
  615.         }
  616.         return scan;
  617.     }
  618.  
  619.     if (scan >= ALT_1 && scan <= ALT_0) {
  620.         scan -= (ALT_1-1);
  621.         if (scan == 10) scan = 0;
  622.         return (scan + '0') | 0x80;
  623.     }
  624.  
  625.     tab = *( ((char **)Keytbl((void *)-1UL, (void *)-1UL, (void *)-1UL)) + 2 );    /* gratuitous (void *) for Lattice */
  626.     scan = tab[scan];
  627.     if (scan >= 'A' && scan <= 'Z') return scan | 0x80;
  628.     return 0;
  629. }
  630.  
  631. long
  632. tty_getchar(f, mode)
  633.     FILEPTR *f;
  634.     int mode;
  635. {
  636.     struct tty *tty = (struct tty *)f->devinfo;
  637.     char c, *tab;
  638.     long r, ret;
  639.     int scan;
  640.     int master = f->flags & O_HEAD;
  641.  
  642.     assert(tty);
  643.  
  644. /* pty masters never worry about job control and always read in raw mode */
  645.     if (master) {
  646.         ret = (*f->dev->read)(f, (char *)&r, 4L);
  647.         return (ret != 4L) ? MiNTEOF : r;
  648.     }
  649.  
  650. /* job control check */
  651.  
  652.     if (tty->pgrp && tty->pgrp != curproc->pgrp) {
  653.         TRACE(("job control: tty pgrp is %d proc pgrp is %d",
  654.             tty->pgrp, curproc->pgrp));
  655.         killgroup(curproc->pgrp, SIGTTIN);
  656.     }
  657.  
  658.     if (mode & COOKED)
  659.         tty->state |= TS_COOKED;
  660.     else
  661.         tty->state &= ~TS_COOKED;
  662.  
  663.     c = UNDEF+1;    /* set to UNDEF when we successfully read a character */
  664.  
  665. /* we may be in the middle of an escape sequence */
  666.     scan = (tty->state & TS_ESC);
  667.     if (scan != 0) {
  668.         if (mode & ESCSEQ) {
  669.             tab = tty->xkey ? tty->xkey : vt52xkey;
  670.             r = (unsigned char) tab[scan++];
  671.             if (r) {
  672.                 c = UNDEF;
  673.                 if (tab[scan] == 0) scan = 0;
  674.             }
  675.             else
  676.                 scan = 0;
  677.             tty->state = (tty->state & ~TS_ESC) | scan;
  678.         }
  679.         else
  680.             tty->state &= ~TS_ESC;
  681.     }
  682.  
  683.     while (c != UNDEF) {
  684.         ret = (*f->dev->read)(f, (char *)&r, 4L);
  685.         if (ret != 4L) {
  686.             DEBUG(("EOF on tty device"));
  687.             return MiNTEOF;
  688.         }
  689.         c = r & 0x00ff;
  690.         scan = (int)((r & 0x00ff0000L) >> 16);
  691.         if ( (c == 0) && (mode & ESCSEQ) && scan) {
  692.             c = UNDEF;
  693.     /* translate cursor keys, etc. into escape sequences or
  694.      * META characters
  695.      */
  696.             r = escseq(tty, scan);
  697.         } else if ((mode & ESCSEQ) && ((scan == CURS_UP && c == '8') ||
  698.                (scan == CURS_DN && c == '2') ||
  699.                (scan == CURS_RT && c == '6') ||
  700.                (scan == CURS_LF && c == '4'))) {
  701.             c = UNDEF;
  702.             r = escseq(tty, scan+0x100);
  703.         } else if (mode & COOKED) {
  704.             if (c == UNDEF)
  705.                 ;    /* do nothing */
  706.             else if (c == tty->ltc.t_dsuspc)
  707.                 killgroup(curproc->pgrp, SIGTSTP);
  708.             else if (c == tty->tc.t_intrc)
  709.                 killgroup(curproc->pgrp, SIGINT);
  710.             else if (c == tty->tc.t_quitc)
  711.                 killgroup(curproc->pgrp, SIGQUIT);
  712.             else if (c == tty->tc.t_stopc)
  713.                 tty->state |= TS_HOLD;
  714.             else if (c == tty->tc.t_startc)
  715.                 tty->state &= ~TS_HOLD;
  716.             else
  717.                 c = UNDEF;
  718.         }
  719.         else
  720.                 c = UNDEF;
  721.     }
  722.  
  723.     if (mode & ECHO)
  724.         tty_putchar(f, r, mode);
  725.  
  726.     return r;
  727. }
  728.  
  729. /*
  730.  * tty_putchar: returns number of bytes successfully written
  731.  */
  732.  
  733. long
  734. tty_putchar(f, data, mode)
  735.     FILEPTR *f;
  736.     long data;
  737.     int mode;
  738. {
  739.     struct tty *tty;
  740.     int master;        /* file is pty master side */
  741.     char ch;
  742.  
  743.     tty = (struct tty *)f->devinfo;
  744.  
  745.     master = f->flags & O_HEAD;
  746.  
  747. /* pty masters don't need to worry about job control */
  748.     if (master) {
  749.         ch = data & 0xff;
  750.  
  751.         if ( (tty->state & TS_COOKED) && ch != UNDEF) {
  752. /* see if we're putting control characters into the buffer */
  753.             if (ch == tty->tc.t_intrc) {
  754.                 tty->state &= ~TS_HOLD;
  755.                 killgroup(tty->pgrp, SIGINT);
  756.                 return 4L;
  757.             }
  758.             else if (ch == tty->tc.t_quitc) {
  759.                 tty->state &= ~TS_HOLD;
  760.                 killgroup(tty->pgrp, SIGQUIT);
  761.                 return 4L;
  762.             }
  763.             else if (ch == tty->ltc.t_suspc) {
  764.                 tty->state &= ~TS_HOLD;
  765.                 killgroup(tty->pgrp, SIGTSTP);
  766.                 return 4L;
  767.             }
  768.             else if (ch == tty->tc.t_stopc) {
  769.                 tty->state |= TS_HOLD;
  770.                 return 4L;
  771.             }
  772.             else if (ch == tty->tc.t_startc) {
  773.                 tty->state &= ~TS_HOLD;
  774.                 return 4L;
  775.             }
  776.             else if (tty->state & TS_HOLD) {
  777.                 return 0;
  778.             }
  779.         }
  780.         goto do_putchar;
  781.     }
  782. /* job control checks */
  783. /* AKP: added T_TOSTOP; don't stop BG output if T_TOSTOP is clear */
  784.     if (tty->pgrp && tty->pgrp != curproc->pgrp &&
  785.              (tty->sg.sg_flags & T_TOSTOP)) {
  786.         TRACE(("job control: tty pgrp is %d proc pgrp is %d",
  787.             tty->pgrp, curproc->pgrp));
  788.         killgroup(curproc->pgrp, SIGTTOU);
  789.     }
  790.  
  791.     if (mode & COOKED) {
  792.         tty->state |= TS_COOKED;
  793.         while (tty->state & TS_HOLD) {
  794. #if 1
  795.     /* hack: BIOS devices != console never reset TS_HOLD themselves
  796.        unless another process happens to call tty_getchar on them while
  797.        we're here.  someone has a better fix? :-(  -nox
  798.     */
  799. /* BIOS device definitions */
  800. #define CONSDEV 2
  801.             short bdev;
  802.             extern DEVDRV bios_tdevice;
  803.  
  804.             if (f->dev == &bios_tdevice &&
  805.                 (bdev=f->fc.aux) != CONSDEV && bconstat(bdev)) {
  806.                 long c = bconin(bdev) & 0x7fffffffL;
  807.  
  808.                 if (c == UNDEF)
  809.                     ;    /* do nothing */
  810.                 else if (c == tty->ltc.t_suspc) {
  811.                     tty->state &= ~TS_HOLD;
  812.                     killgroup(tty->pgrp, SIGTSTP);
  813.                 } else if (c == tty->tc.t_intrc) {
  814.                     tty->state &= ~TS_HOLD;
  815.                     killgroup(tty->pgrp, SIGINT);
  816.                 } else if (c == tty->tc.t_quitc) {
  817.                     tty->state &= ~TS_HOLD;
  818.                     killgroup(tty->pgrp, SIGQUIT);
  819.                 } else if (c == tty->tc.t_startc)
  820.                     tty->state &= ~TS_HOLD;
  821.             }
  822. #endif
  823.             nap(60);    /* sleep for 60 milliseconds */
  824.         }
  825.     }
  826.     else
  827.         tty->state &= ~TS_COOKED;
  828.  
  829. do_putchar:
  830.     return (*f->dev->write)(f, (char *)&data, 4L);
  831. }
  832.